package com.example.redisspringboot.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author lichenyang
 * @create 2021-05-09 4:01 下午
 */
@RestController
@RequestMapping("distributeLock")
public class DistributeLock {

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("testLock")
    public void testLock() {
        //1获取锁，setne
//        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
        // 设置带有过期时间的锁
//        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111", 10, TimeUnit.SECONDS);
        // 设置带有uuid的锁
        String uuId = UUID.randomUUID().toString();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuId, 10, TimeUnit.SECONDS);

        //2获取锁成功、查询num的值
        if (lock) {
            Object value = redisTemplate.opsForValue().get("num");
            //2.1判断num为空return
            if (StringUtils.isEmpty(value)) {
                return;
            }
            //2.2有值就转成int
            int num = Integer.parseInt(value + "");
            //2.3把redis的num加1
            redisTemplate.opsForValue().set("num", ++num);
            //2.4释放锁，del
            // (获取锁 并释放锁并不是原子性的, 有可能比较 uuId, uuidVal的时候 比较成功, 但是锁过期了, 此时还是执行删除操作了,但是删除操作的时候 删除的是其他锁的)
            // 归根结底就是不能让锁的名称相同
            String uuidVal = (String)redisTemplate.opsForValue().get("lock");
            if(Objects.equals(uuidVal,uuId)){
                redisTemplate.delete("lock");
            }

        } else {
            //3获取锁失败、每隔0.1秒再获取
            try {
                Thread.sleep(100);
                testLock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}
